package com.example.state.machine.service.impl;

import com.example.state.machine.entity.Product;
import com.example.state.machine.enums.OrderEvent;
import com.example.state.machine.enums.OrderState;
import com.example.state.machine.service.OrderService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.data.ActionRepository;
import org.springframework.statemachine.data.GuardRepository;
import org.springframework.statemachine.data.StateRepository;
import org.springframework.statemachine.data.TransitionRepository;
import org.springframework.statemachine.data.jpa.JpaRepositoryAction;
import org.springframework.statemachine.data.jpa.JpaRepositoryGuard;
import org.springframework.statemachine.data.jpa.JpaRepositoryState;
import org.springframework.statemachine.data.jpa.JpaRepositoryTransition;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    private final Map<Long, Order> orderMap = new ConcurrentHashMap<>();

    @Resource
    private StateMachineFactory<OrderState, OrderEvent> stateMachineFactory;

    @Resource
    StateRepository<JpaRepositoryState> stateRepository;

    @Resource
    TransitionRepository<JpaRepositoryTransition> transitionRepository;

    @Resource
    ActionRepository<JpaRepositoryAction> actionRepository;

    @Resource
    GuardRepository<JpaRepositoryGuard> guardRepository;

    /**
     * 创建新订单
     *
     * @param product 订单请求参数（DTO）
     * @return 创建的订单实体
     */
    @Transactional
    @Override
    public Order createOrder(Product product) {
        // 1. 创建订单实体并保存到数据库
        Order order = new Order();
        order.setOrderId(Long.valueOf(UUID.randomUUID().toString()));
        order.setProductId(product.getProductId());
        order.setAmount(product.getPrice());
        order.setState(OrderState.UNPAID);  // 初始状态为 INIT
        // order = orderRepository.save(order);
        orderMap.put(order.getOrderId(), order);

        System.out.println("正在创建订单，订单号：" + order.getOrderId());

        // 每个订单拥有独立的状态机实例，避免多订单操作时的状态冲突
        // 2. 初始化订单对应的状态机（绑定订单ID）
        StateMachine<OrderState, OrderEvent> stateMachine =
                stateMachineFactory.getStateMachine(order.getOrderId().toString());
        stateMachine.startReactively().subscribe();  // 启动状态机，进入初始状态

        return order;
    }

    /**
     * 处理支付操作
     *
     * @param orderId 订单ID
     */
    @Transactional
    @Override
    public void payOrder(Long orderId) {
        System.out.println("尝试支付，订单号：" + orderId);
        // System.out.println(" 支付失败, 状态异常，订单号：" + orderId);
        Order order = orderMap.get(orderId);

        // 1. 获取该订单的状态机实例
        StateMachine<OrderState, OrderEvent> stateMachine =
                stateMachineFactory.getStateMachine(orderId.toString());

        // 2. 检查当前状态是否允许支付
        if (!stateMachine.getState().getId().equals(OrderState.UNPAID)) {
            throw new IllegalStateException("当前状态不允许支付");
        }

        // 3. 扣减库存（业务逻辑）
        // inventoryService.decreaseStock(order.getProductId(), order.getAmount());

        // 4. 发送支付事件到状态机，触发状态转换
        Message<OrderEvent> orderEventMessage = MessageBuilder.withPayload(OrderEvent.PAY)
                .setHeader("orderId", orderId).build();
        stateMachine.sendEvent(Mono.just(orderEventMessage))
                .subscribe(); // 必须订阅才会触发

        // 5. 更新订单状态到数据库
        order.setState(stateMachine.getState().getId());
        // orderRepository.save(order);
        orderMap.put(orderId, order);
    }

    /**
     * 发货操作
     *
     * @param orderId 订单ID
     */
    @Transactional
    @Override
    public void shipOrder(Long orderId) {
        System.out.println(" 尝试发货，订单号：" + orderId);
        // System.out.println(" 发货失败，状态异常，订单号：" + orderId);
        Order order = orderMap.get(orderId);

//        Order order = orderRepository.findById(orderId)
//                .orElseThrow(() -> new IllegalArgumentException("订单不存在"));

        StateMachine<OrderState, OrderEvent> stateMachine =
                stateMachineFactory.getStateMachine(orderId.toString());

        // 状态机自动校验状态流转规则
        // 发送发货事件，数据流作为事件序列，通过订阅（subscribe）触发处理逻辑。
        // 构建消息对象
        Message<OrderEvent> event = MessageBuilder
                .withPayload(OrderEvent.SHIP)
                .setHeader("orderId", orderId) // 设置消息头，需确保状态机通过 orderId 能定位到正确的订单实例。
                .build();

        stateMachine.sendEvent(Mono.just(event))
                .doOnNext(result -> { // 处理每个结果元素
                    log.info("状态转换结果: {}", result);
                })
                .doOnError(e -> log.error("发送事件失败", e)) // 记录错误日志
                .subscribe(
                        result -> {
                        }, // 等效于 doOnNext，可留空（已用 doOnNext 处理）,
                        e -> {/* 错误处理 */}, // 参数2：onError 回调：处理流中的异常（如状态机处理失败）。必须定义，否则异常会被静默吞没（尤其在生产环境需显式处理错误）。 // 等效于 doOnError，可留空
                        () -> log.info("完成") // 参数3：oonComplete 回调：流正常结束时触发（如事件成功发送到状态机）。可选，用于记录完成日志或清理资源。
                ); // 4. 订阅触发操作，subscribe() 触发实际的事件发送（无订阅则不会执行）。

        // 更新状态并触发物流通知
        order.setState(OrderState.SHIPPED);
        orderMap.put(orderId, order);
        // orderRepository.save(order);
        // notifyLogistics(order); // 调用物流服务
    }

    /**
     * 收货操作
     *
     * @param orderId 订单ID
     */
    @Override
    public void receiveOrder(Long orderId) {
        Order order = orderMap.get(orderId);
        System.out.println(" 尝试收货，订单号：" + orderId);
        // System.out.println(" 收货失败，状态异常，订单号：" + orderId);

        StateMachine<OrderState, OrderEvent> stateMachine =
                stateMachineFactory.getStateMachine(orderId.toString());

        // 发送收货事件
        stateMachine.sendEvent(Mono.just(MessageBuilder.withPayload(OrderEvent.CONFIRM).setHeader("orderId", orderId).build())).subscribe();

        order.setState(OrderState.COMPLETED);
    }

    /**
     * 取消订单
     *
     * @param orderId 订单ID
     */
    @Transactional
    @Override
    public void cancelOrder(Long orderId) {
//        Order order = orderRepository.findById(orderId)
//                .orElseThrow(() -> new IllegalArgumentException("订单不存在"));

        Order order = orderMap.get(orderId);

        StateMachine<OrderState, OrderEvent> stateMachine =
                stateMachineFactory.getStateMachine(orderId.toString());

        // 仅允许在 UNPAID 状态取消
        if (!stateMachine.getState().getId().equals(OrderState.UNPAID)) {
            throw new IllegalStateException("订单已支付，无法取消");
        }
        // 发送取消事件
        stateMachine.sendEvent(Mono.just(MessageBuilder.withPayload(OrderEvent.CANCEL).setHeader("orderId", orderId).build())).subscribe();

        // 更新状态并触发短信通知
        order.setState(OrderState.CANCELLED);
        orderMap.put(orderId, order);
        // orderRepository.save(order);
        // refundPayment(order); // 调用退款服务（若已支付）
    }

    // 查询订单
    @Override
    public Order getOrder(Long orderId) {
        return orderMap.get(orderId);
    }


    // 触发状态转换事件（核心方法）
//    public void triggerEvent(Long orderId, OrderEvent event) {
//        // 1. 获取状态机实例
//        StateMachine<OrderState, OrderEvent> stateMachine = stateMachineFactory.getStateMachine();
//
//        // 2. 重置状态机并关联订单的当前状态
//        stateMachine.getStateMachineAccessor()
//                .doWithAllRegions(access -> {
//                    access.resetStateMachine(new DefaultStateMachineContext<>(OrderState.UNPAID, null, null, null));
//                    access.setReloadFunction(ctx -> orderStatePersist.read(orderId));
//                });
//
//        // 3. 启动状态机并发送事件
//        stateMachine.startReactively().subscribe();
//        Order order = getOrder(orderId);
//        Message<OrderEvent> message = MessageBuilder
//                .withPayload(event)
//                .setHeader("order", order)  // 传递订单信息（供守卫条件使用）
//                .build();
//        boolean eventAccepted = stateMachine.sendEvent(message);
//
//        // 4. 持久化状态并停止状态机
//        if (eventAccepted) {
//            orderStatePersist.write(stateMachine.getState().getId(), orderId);
//        }
//        stateMachine.stopReactively();
//    }

}
